
package view;

import controllers.CreateReport;
import controllers.FormReportValidator;
import controllers.LoginServiceControl;
import controllers.ReportHistoryController;
import controllers.ServiceControl;
import entities.AmountRange;
import java.io.File;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Iterator;
import java.util.List;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.concurrent.Task;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.HPos;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.control.*;
import javafx.scene.layout.GridPane;
import javafx.scene.layout.HBox;
import javafx.stage.FileChooser;
import javafx.stage.Stage;
import ws.login.NormalizedListEstablishment;
import vo.ReportVO;

/**
 * @version 1.0
 * @date 13/04/2012
 * @author john
 */
public class StatsPane extends GridPane{
    
    private final static int[][] amountRanges={{-1,-1},{0,50000},{50000,100000},{100000,250000},{250000,500000},{500000,1000000},{1000000,5000000},{5000000,-1}};
    
    private final double minTFWidth=200;
    private final double minCBWidth=200;
    private String initDateText="aaaa/mm/dd";
    
    private final ObservableList reportTypesList;
    private final ObservableList franchisesList;
    private final ObservableList establishmentsList;
    private final ObservableList<AmountRange> amountRangesList;
    private ArrayList<String> establishmentsIdsList = new ArrayList<String>();
    private ArrayList<String> franchisesIdsList = new ArrayList<String>();
    
    private HBox reportTypeHBox;
    private GridPane filterParamGrid;
    private Label reportTypeL;
    private Label startDateL;
    private Label endDateL;
    private Label franchiseL;
    private Label stablishmentL;
    private Label amountRangeL;
    private TextField startDateTF;
    private TextField endDateTF;
    private ChoiceBox reportTypeCB;
    private ChoiceBox franchiseCB;
    private ChoiceBox stablishmentCB;
    private ChoiceBox amountRangeCB;
    private Button seeReportB;
    
    private Tooltip startDateT;
    private Tooltip endDateT;
    private Tooltip fileSelectedT;
    
    private ServiceControl serviceControl = new ServiceControl();
    private CreateReport createReportControl = new CreateReport();

    public StatsPane(final Stage primaryStage) {
        setId("stats-pane");
        setAlignment(Pos.CENTER);
        setPadding(new Insets(30, 30, 30, 30));
        setHgap(0);
        setVgap(20);
        reportTypesList=FXCollections.observableArrayList();
        franchisesList=FXCollections.observableArrayList();
        establishmentsList=FXCollections.observableArrayList();
        amountRangesList=FXCollections.observableArrayList();
        initTooltips();
        initReportTypeHBox();
        initFilterParamGrid();
        seeReportB=new Button("Ver reporte");
        seeReportB.setOnAction(createReport(primaryStage,this));
        GridPane.setHalignment(seeReportB, HPos.RIGHT);
        add(reportTypeHBox,0,0);
        add(filterParamGrid,0,1);
        add(seeReportB,0,2);
    }
    
    /**
     * 
     */
    private void initTooltips(){
        startDateT=TooltipBuilder.create()
            .text("Fecha inválida")
            .hideOnEscape(true)
            .autoHide(true)
            .build();
        endDateT=TooltipBuilder.create()
            .text("Fecha inválida")
            .hideOnEscape(true)
            .autoHide(true)
            .build();
        fileSelectedT=TooltipBuilder.create()
            .text("¡Debe seleccionar un archivo!")
            .hideOnEscape(true)
            .autoHide(true)
            .build();
    }
    
    /**
     * 
     */
    private void fillReportTypesList(){
        List<String> list = serviceControl.getReportTypes();
        reportTypesList.setAll(list);
    }
    
    /**
     * 
     */
    private void fillAmountRangesList(){
        amountRangesList.clear();
        for (int[] range : amountRanges) 
            amountRangesList.add(new AmountRange(range[0], range[1]));
    }
    
    /**
     * 
     */
    private void fillFranchisesList(){
        String allFranchises="Todas";
        // Esto es de prueba, debe llamar a un metodo control para recuperar todas las franquicias que esten registradas
        String franchisesTest1="VISA";
        String franchisesTest2="MasterCard";
        String franchisesTest3="American Express";
        franchisesIdsList = new ArrayList();
        franchisesIdsList.add("0");
        franchisesIdsList.add("1");
        franchisesIdsList.add("2");
        franchisesIdsList.add("3");
        franchisesList.setAll(
            allFranchises,
            new Separator(),
            franchisesTest1,
            franchisesTest2,
            franchisesTest3
        );
    }
    
    /**
     * 
     */
    private void fillBranchOfficesList(){
        LoginServiceControl loginControl = new LoginServiceControl();
        establishmentsList.add("Todas");
        establishmentsList.add(new Separator());
        establishmentsIdsList.add("0");
        for (Iterator<NormalizedListEstablishment> it = loginControl.listBrand(MainWindow.getActiveUser().getBrandName()).iterator(); it.hasNext();) {
            NormalizedListEstablishment e = (NormalizedListEstablishment) it.next();
            establishmentsList.add(e.getBrandName());
            establishmentsIdsList.add(e.getBrandId());
        }
    }
    
    /**
     * 
     */
    private void initReportTypeHBox(){
        reportTypeHBox=new HBox(40);
        reportTypeHBox.setPadding(new Insets(20, 0, 0, 0));
        reportTypeL=new Label("Ver reporte de:");
        fillReportTypesList();
        reportTypeCB=new ChoiceBox<String>(reportTypesList);
        reportTypeCB.getSelectionModel().select(reportTypesList.get(0));
        reportTypeHBox.getChildren().setAll(reportTypeL,reportTypeCB);
    }
    
    /**
     * 
     */
    private void initFilterParamGrid(){
        fillFranchisesList();
        fillBranchOfficesList();
        fillAmountRangesList();
        filterParamGrid=new GridPane();
        filterParamGrid.setPadding(new Insets(30));
        filterParamGrid.setHgap(25);
        filterParamGrid.setVgap(10);
        filterParamGrid.setId("filters-pane");
        startDateL=new Label("Fecha inicial:");
        endDateL=new Label("Fecha final:");
        franchiseL=new Label("Franquicia:");
        stablishmentL=new Label("Sucursal:");
        amountRangeL=new Label("Monto:");
        startDateTF=new TextField();
        startDateTF.setPromptText(initDateText);
        endDateTF=new TextField();
        endDateTF.setPromptText(initDateText);
        amountRangeCB=new ChoiceBox(amountRangesList);
        amountRangeCB.getSelectionModel().select(amountRangesList.get(0));
        franchiseCB=new ChoiceBox(franchisesList);
        franchiseCB.getSelectionModel().select(franchisesList.get(0));
        stablishmentCB=new ChoiceBox(establishmentsList);
        stablishmentCB.getSelectionModel().select(establishmentsList.get(0));
        startDateTF.setMinWidth(minTFWidth);
        endDateTF.setMinWidth(minTFWidth);
        amountRangeCB.setMinWidth(minCBWidth);
        franchiseCB.setMinWidth(minCBWidth);
        stablishmentCB.setMinWidth(minCBWidth);
        filterParamGrid.add(startDateL,0,0);
        filterParamGrid.add(endDateL,0,1);
        filterParamGrid.add(stablishmentL,0,2);
        filterParamGrid.add(startDateTF,1,0);
        filterParamGrid.add(endDateTF,1,1);
        filterParamGrid.add(stablishmentCB,1,2);
        filterParamGrid.add(franchiseL,2,0);
        filterParamGrid.add(amountRangeL,2,2);
        filterParamGrid.add(franchiseCB,3,0);
        filterParamGrid.add(amountRangeCB,3,2);
    }
    
    /**
     * 
     * @param primaryStage
     * @param statsPane
     * @return 
     */
    private EventHandler<ActionEvent> createReport(final Stage primaryStage,final GridPane statsPane){
        return new EventHandler<ActionEvent>() {
            @Override
            public void handle(ActionEvent event) {
                boolean validInfo=true;
                boolean checkStartDate=true;
                boolean checkEndDate=true;
                if (startDateTF.getText().toString().trim().equals(""))
                    checkStartDate=false;
                if (endDateTF.getText().toString().trim().equals(""))
                    checkEndDate=false;
                final AmountRange amountRange = (AmountRange)(amountRangeCB.getSelectionModel().getSelectedItem());
                double initialAmountValue = amountRange.getMin();
                double finalAmountValue = amountRange.getMax();
                String startDateValue = "0001/01/01";
                Calendar today=Calendar.getInstance();
                int month=(today.get(Calendar.MONTH)+1);
                int day=today.get(Calendar.DAY_OF_MONTH);
                String monthS=month<10?"0"+month:month+"";
                String dayS=day<10?"0"+day:day+"";
                String endDateValue=today.get(Calendar.YEAR)+"/"+monthS+"/"+dayS;
                if(checkStartDate){
                    if (!FormReportValidator.syntacticValidationDate(startDateTF.getText())){
                        startDateT.show(startDateL,
                            primaryStage.getX()+
                            startDateL.getLayoutX()+
                            20+
                            (primaryStage.getWidth()-filterParamGrid.getWidth())/2,
                            primaryStage.getY()+
                            startDateL.getLayoutY()+
                            filterParamGrid.getLayoutY()+
                            filterParamGrid.getPadding().getBottom()+
                            filterParamGrid.getPadding().getTop());
                        validInfo=false;
                    }else{
                        startDateValue = startDateTF.getText();
                    }
                }
                if(checkEndDate){
                    if (!FormReportValidator.syntacticValidationDate(endDateTF.getText())){
                        endDateT.show(endDateL,
                            primaryStage.getX()+
                            endDateL.getLayoutX()+
                            20+
                            (primaryStage.getWidth()-filterParamGrid.getWidth())/2,
                            primaryStage.getY()+
                            endDateL.getLayoutY()+
                            filterParamGrid.getLayoutY()+
                            filterParamGrid.getPadding().getBottom()+
                            filterParamGrid.getPadding().getTop());
                        validInfo=false;
                    }else{
                        endDateValue = endDateTF.getText();
                    }
                }
                if(validInfo){
                    FileChooser fileSelector = new FileChooser();
                    File fileToSave = fileSelector.showSaveDialog(primaryStage);
                    if (fileToSave == null){
                        fileSelectedT.show(seeReportB,
                            primaryStage.getX()+
                            seeReportB.getLayoutX()-
                            170,
                            primaryStage.getY()+
                            seeReportB.getLayoutY()+
                            getVgap()*2);
                    }else {
                        final String startDateValueF=startDateValue;
                        final String endDateValueF=endDateValue;
                        final File fileToSaveF=fileToSave;
                        final double initialAmountValueF=initialAmountValue;
                        final double finalAmountValueF=finalAmountValue;
                        Task createReportTask=new Task() {
                            @Override
                            protected Object call() throws Exception {
                                boolean result = createReportControl.createReport(fileToSaveF, serviceControl.getTransactions(startDateValueF, 
                                endDateValueF, establishmentsIdsList.get(stablishmentCB.getSelectionModel().getSelectedIndex()), 
                                MainWindow.getActiveUser().getBrandId(), franchisesIdsList.get(franchiseCB.getSelectionModel().getSelectedIndex()), 
                                reportTypeCB.getSelectionModel().getSelectedItem().toString(), initialAmountValueF, finalAmountValueF), MainWindow.getActiveUser(),
                                reportTypeCB.getSelectionModel().getSelectedItem().toString());
                                if (result){
                                    String issueDate=java.util.Calendar.getInstance().getTime().toString();
                                    String location=fileToSaveF.getAbsolutePath();
                                    String type=reportTypeCB.getSelectionModel().getSelectedItem().toString();
                                    String franchise=franchiseCB.getSelectionModel().getSelectedItem().toString();
                                    String branch=stablishmentCB.getSelectionModel().getSelectedItem().toString();
                                    String amount=amountRange.toString();
                                    ReportVO reportVO=new ReportVO(issueDate, location, type, franchise, branch, startDateValueF, endDateValueF, amount);
                                    boolean saveReportResult = ReportHistoryController.saveReport(reportVO);
                                    if(!saveReportResult)
                                        System.err.println("No se pudo guardar la entrada del reporte en el historial");
                                    updateMessage("Reporte terminado");
                                }
                                else
                                    updateMessage("Error");
                                return true;
                            }
                        };
                        createReportTask.messageProperty().addListener(new ChangeListener<String>() {
                            @Override
                            public void changed(ObservableValue<? extends String> ov, String oldMessage, String newMessage) {
                                if(!newMessage.equals("Error"))
                                    new ReportResultDialog(statsPane, primaryStage, "Reporte terminado", "El reporte se ha guardado en "+fileToSaveF.getAbsolutePath(), true).show();
                                else
                                    new ReportResultDialog(statsPane, primaryStage, "Error", "Ocurrió un error en la creación del reporte.", false).show();
                            }
                        });
                        new Thread(createReportTask).start();
                        new ReportResultDialog(statsPane, primaryStage, "Confirmación", "Reporte en construcción.", false).show();
                    }
                }
            }
        };
    }
    
    /**
     * 
     */
    protected void cleanFields(){
        startDateTF.setText("");
        endDateTF.setText("");
        reportTypeCB.getSelectionModel().select(0);
        franchiseCB.getSelectionModel().select(0);
        stablishmentCB.getSelectionModel().select(0);
        amountRangeCB.getSelectionModel().select(0);
    }
    
}
